#include "simodo/inout/token/Tokenizer.h"
#include "simodo/inout/log/Logger.h"
#include "DocumentOperationFactory.h"
#include "fuze/FuzeDocumentOperation.h"
#include "script/ScriptSemanticTokenLegend.h"

using namespace simodo;

int main(int argc, char *argv[])
{
    std::string                   semantics_dir;
    std::string                   modules_dir;
    std::string                   grammar_dir;
    inout::Logger::SeverityLevel  log_level = inout::Logger::SeverityLevel::Info;
    bool                          save_mode = false;
    std::unique_ptr<std::ostream> log_stream;
    std::unique_ptr<std::istream> in;

    if (argc > 1)
        semantics_dir = argv[1];

    if (argc > 2)
        modules_dir = argv[2];

    if (argc > 3)
        grammar_dir = argv[3];

    if (argc > 4)
        log_stream = std::make_unique<std::ofstream>(argv[4]);

    if (argc > 5)
    {
        if (std::string(argv[5]) == "Debug")
            log_level = inout::Logger::SeverityLevel::Debug;
        else if (std::string(argv[5]) == "Info")
            log_level = inout::Logger::SeverityLevel::Info; // -V1048
        else if (std::string(argv[5]) == "Warning")
            log_level = inout::Logger::SeverityLevel::Warning;
        else if (std::string(argv[5]) == "Error")
            log_level = inout::Logger::SeverityLevel::Error;
        else if (std::string(argv[5]) == "Critical")
            log_level = inout::Logger::SeverityLevel::Critical;
    }

    if (argc > 6)
        save_mode = std::string(argv[6]) == "save";

    if (argc > 7)
#ifdef CROSS_WIN
        in = std::make_unique<std::ifstream>(simodo::inout::fromUtf8CharToWChar(argv[7]).c_str());
#else
        in = std::make_unique<std::ifstream>(argv[7]);
#endif
    inout::Logger log(log_stream ? *log_stream : std::cerr,
                    "SIMODO-LSP", 
                    log_level);

    lsp::ServerCapabilities server_capabilities;

    server_capabilities.hoverProvider = true;
    server_capabilities.documentSymbolProvider = true;
    server_capabilities.declarationProvider = true;
    server_capabilities.definitionProvider = true;
    server_capabilities.completionProvider.triggerCharacters = {u"."};
    server_capabilities.completionProvider.resolveProvider = false;
    server_capabilities.completionProvider.completionItem.labelDetailsSupport = false;
    server_capabilities.semanticTokensProvider.legend = SCRIPT_SEMANTIC_TOKENS_LEGEND;

    lsp::SimodoCapabilities simodo_capabilities;

    simodo_capabilities.runnerProvider  = true;
    simodo_capabilities.runnerOptions   = {
                                            {u"fuze",           SLR_method_report},
                                            {u"fuze",           LR1_method_report}, 
                                            {u"simodo-script",  execution_report},
                                            // {u"teragraph",      execution_report},
                                        };

    DocumentOperationFactory factory(semantics_dir, modules_dir, grammar_dir);

    lsp::ServerContext server(u"SIMODO",
                              server_capabilities,
                              simodo_capabilities,
                              factory,
                              log,
                              in ? *in : std::cin,
                              std::cout,
                              save_mode);

    server.run();

    return 0;
}